<?php
declare(strict_types=1);
namespace Service\VenderClient\PayCenterApi;
use Service\Code\Normal;
use Service\BaseService;
use Service\ExtraService\TaskWorker;

class HelipayApiClient extends BaseService
{ 
    private $config;
    private $url=[
        //合力宝网关
        'helipayGateWay'                => 'https://pay.trx.helipay.com',
        //支付单报关接口
        'orderApplyCustom'              => '/trx/applyCustoms/interface.action',
        'orderQueryCustom'              => '/trx/applyCustoms/interface.action',

        //小程序支付网关
        'orderMnAppPay'                 => '/trx/app/interface.action',

        //收银台扫码支付
        'orderCasherScanPay'            => '/trx/app/interface.action',
        
        //小程序支付和收银公用查询和退款
        'orderPayQuery'                 => '/trx/app/interface.action',
        'orderPayRefund'                => '/trx/app/interface.action',
        'orderPayRefundQuery'           => '/trx/app/interface.action',

        //PC web 收银台支付网关
        'ordeWebCashPayGateWay'         => '/trx/universalcashier',
        'ordeWebCashPay'                => '/trx/universalcashier/unifiedorder',
        'ordeWebCashPayQuery'           => '/trx/universalcashier/query',
        'ordeWebCashPayRefund'          => '/trx/universalcashier/refund',
        'ordeWebCashPayRefundQuery'     => '/trx/universalcashier/refundQuery',

        //进件开户信息
        'merchantOpenGateWay'           => '/trx/merchantEntry/interface.action',
        'sp_register'                   => '/trx/merchantEntry/interface.action',
        'registerQuery'                 => '/trx/merchantEntry/interface.action',
        'openProduct'                   => '/trx/merchantEntry/interface.action',
        'getProductConfig'              => '/trx/merchantEntry/interface.action',
        'modifyProductConfig'           => '/trx/merchantEntry/interface.action',
        'userMerchantInfoQuery'         => '/trx/merchantEntry/interface.action',
        //电子合同签章
        'contractQuery'                 => '/trx/merchantEntry/interface.action',
        'signContract'                  => '/trx/merchantAgreement/signContract.action',
        //回调功能
        'orderCallBackUrl'              => 'http://testpssnotify.indoorbuy.com/Notify/index/userType/helipay/messageType/OrderNotify',
        'OpenUserCallBackUrl'           => 'http://testpssnotify.indoorbuy.com/Notify/index/userType/helipay/messageType/UserNotify',
        'UserConstractCallBackUrl'      => 'http://testpssnotify.indoorbuy.com/Notify/index/userType/helipay/messageType/ContracctNotify',
        'orderMnAppPayRefundNotifyUrl'  => 'http://testpssnotify.indoorbuy.com/Notify/index/userType/helipay/messageType/orderMnAppPayRefundNotify',
        'ordeWebCashPayRefundNotifyUrl'   => 'http://testpssnotify.indoorbuy.com/Notify/index/userType/helipay/messageType/ordeWebCashPayRefundNotify',
        'orderApplyCustomNotifyUrl'     => 'http://testpssnotify.indoorbuy.com/Notify/index/userType/helipay/messageType/orderApplyCustomNotify',
    ];
    private $noSignData=[
        'P21_identity',
        'timeExpire'
    ];
    public function __construct( array $config = [])
    {
        $this->config =$config;
        $customerPrivateKeyPath = __DIR__.'/HelipayKey/'.$this->config['customerPrivateKey'];
        $helipayPublicKeyPath = __DIR__.'/HelipayKey/'.$this->config['helipayPublicKey'];
        if(!file_exists($customerPrivateKeyPath)){
            throw new \Exception('处理失败【合利宝支付缺少商户私钥文件，请联系管理员配置】 ' );
        }
        if(!file_exists($helipayPublicKeyPath)){
            throw new \Exception('处理失败【合利宝缺少支付公钥文件，请联系管理员配置】' );
        }
    }
    
    /**
     * 商户进件开户注册接口
     * 用于分账
     * @param array $param
     */
    public function userRegister( array $param = [] )
    {
        $data = [
            'firstClassMerchantNo'      => $this->config['customerNumber'],//合利宝下发的，以C开头的商户编号
            'orderNo'                   => "p_".date("YmdHis"),//商户系统内部请求订单号，要求50字符以内，同一商户号下请求订单号唯一
            'signName'                  => $this->config['customerNumber'],//子商户签约名
            'merchantType'              => 'ENTERPRISE',//见附录5.7 注：1.填写英文类别；2.个人、企业、个体商户交易限额不同，切勿传错
            'role'                      => 'SELLER',//BUYER 买方SELLER 卖方（买方只能是个人类型商户）
            'legalPerson'               => '陈树波',//名字或法人姓名
            'legalPersonID'             => '440101199201010171',//身份证
            'idType'                    => 'IDCARD',//证件类型
            'idCardStartDate'           => '20220630',//身份证开始日期
            'idCardEndDate'             => '20420630',//身份证结束日期
            'linkman'                   => '李四',//联系人（非个人类必填）
            'linkPhone'                 => '15228257236',//联系电话（非个人类必填）
            'linkManId'                 => '440101199201010171',//联系人身份证号，非个人类必填
            'bankCode'                  => '102100000048',//结算卡联行号
            'settlementPhoneNo'         => '15228257236',//结算人手机号
            'accountName'               => '张三',//结算银行卡开户名
            'accountNo'                 => '907190100001000014',//结算银行卡账号
            'settleBankType'            => 'TOPRIVATE',//对公TOPUBLIC，对私TOPRIVATE
            'businessLicense'           => '445221144522119998',//营业执照号,非个人必传
            'address'                   => '中国四川省成都市皇家一号',//注册地址
            'businessDateStart'         => date("Ymd"),//经营起始日期,非个人必传
            'businessDateLimit'         => date("Ymd"),//经营结束日期,非个人必传
            'callbackUrl'               => $this->url['OpenUserCallBackUrl'],//人工审核后异步回调地址（返回参数为JSON数据）注：人工审核成功或失败会异步通知；自动审核通过，不会通知
        ];
        return $this->execute('sp_register',$data);
    }
    
    /**
     * 商户信息查询
     * 用于分账
     * @param array $param
     */
    public function userMerchantInfoQuery( array $param = [] )
    {
        $data = [
            'merchantNo'            => 'E1800001025',//子商户号
            'firstClassMerchantNo'  => $this->config['customerNumber'],//平台商商编
        ];
        return $this->execute('userMerchantInfoQuery',$data);
    }
    
    /**
     * 进件查询接口
     * 用于分账
     * @param array $param
     */
    public function userRegisterQuery( array $param = [] )
    {
        $data = [
            'orderNo'               => "p_".date("YmdHis"),//商户系统内部请求订单号，要求50字符以内，同一商户号下请求订单号唯一
            'signName'              => '麦帮科技',
            'firstClassMerchantNo'  => $this->config['customerNumber'],//合利宝下发的，以C开头的商户编号
        ];
        return $this->execute('registerQuery',$data);
    }
    
    /**
     * 进件产品开通接口
     * 用于分账
     * @param array $param
     */
    public function userOpenProduct( array $param = [] )
    {
        $data = [
            'productType'           => 'TRANSFER',//代付产品
            'firstClassMerchantNo'  => $this->config['customerNumber'],//平台商编号
            'merchantNo'            => 'E1800001025',//进件审核通过后才有的商户号
            'calcType'              => 'RATIO',//计算类型SINGLE	单笔收费 RATIO	比率收费
            'moneyPeriod'           => $this->config['customerNumber'],//资金周期
            'onlineBankType'        => $this->config['customerNumber'],//账户属性
            'value'                 => '0.003',//费率
            'floating'              => '0.001',//浮动值
            'minFee'                => '0.000',//最低费率金额
        ];
        return $this->execute('openProduct',$data);
    }
    
    /**
     * 进件产品手续费查询
     * 用于分账
     * @param array $param
     */
    public function userGetProductConfig( array $param = [] )
    {
        $data = [
            'merchantNo'            => 'E1800001025',//进件审核通过后才有的商户号，子商户编号
            'type'                  => 'FeeCollection',//类型
            'productType'           => 'APPPAY',//产品类型
        ];
        return $this->execute('getProductConfig',$data);
    }
    
    /**
     * 产品手续费收取模式修改
     * @param array $param
     */
    public function userModifyProductConfig( array $param = [] )
    {
        $data = [
            'merchantNo'    => 'E1800001025',//进件审核通过后才有的商户号，子商户编号
            'type'          => 'FeeCollection',//类型
            'productType'   => 'APPPAY',//产品类型
            'value'         => 'FEEACCOUNT',//交易手续费收取方式（自身资金账户、平台商手续费账号），见附录5.22
        ];
        return $this->execute('modifyProductConfig',$data);
    }
    
    /**
     * 签署信息提交由合利宝系统
     * 电子合同签署接口
     * @param array $param
     */
    public function userSignContract( array $param = [] )
    {
        $data = [
            'merchantNo'    => $this->config['customerNumber'],//平台商编号
            'interfaceName' => 'signContract',//接口名称
            'email'         => '1044108951@qq.com',//邮箱
            'phone'         => '15228257123',//手机号
            'legalPersonID' => '510521198908087100',//申请合同的商户身份证号
            'legalPerson'   => '陈陈',//申请合同的商户法人姓名
            'signName'      => '小陈哥',//公司名称
            'address'       => '四川省成都市',//商户地址
            'callBackUrl'   => $this->url['UserConstractCallBackUrl'],//交易手续费收取方式（自身资金账户、平台商手续费账号），见附录5.22
        ];
        return $this->execute('signContract',$data);
    }
    
    /**
     * 签章查询接口
     * 电子合同签署接口
     * @param array $param
     */
    public function userContractQuery( array $param = [] )
    {
        $data = [
            'merchantNo' => 'E1800001025',//子商户号
        ];
        return $this->execute('contractQuery',$data);
    }
    
    /**
     * 收银台支付接口
     * @param array $param
     */
    public function ordeWebCashPay( array $param = [] )
    {
        $data = [
            'orderId'               => '20170302000001',
            'goodsName'             => '在线下单',//订单号
            'orderAmount'           => '0.01',
            'curreney'              => 'CNY',
            'period'                => '300',
            'serverCallbackUrl'     => $this->config['orderCallBackUrl'],
            'desc'                  => '在线扫码支付',
            'payerName'             => '陈树波',
            'idCardNo'              => '510521198908087579',
            'industryType'          => 'E_BUSINESS',
            'periodUnit'            => 'minute',
            'period'                => '10',
            /* 'ruleJson'              => json_encode([
                [
                    'splitBillMerchantNo'   => '分账商户号',
                    'splitBillAmount'       => '分账金额'
                ]
            ],JSON_UNESCAPED_UNICODE),
            'industryType'          => 'E_BUSINESS',
            'payType'               => 'WXPAY_SDK',
            'payAppid'              => '445454545',
            'payInfoType'           => 'payInfo' */
        ];
        return $this->execute('ordeWebCashPay',$data);
    }
    
    /**
     * 收银台支付订单查询
     * @param array $param
     */
    public function ordeWebCashPayQuery( array $param = [] )
    {
        $data = [
            'orderId'               => '20170302000001',
            /* 'ruleJson'              => json_encode([
                [
                    'splitBillMerchantNo'   => '分账商户号',
                    'splitBillAmount'       => '分账金额'
                ]
            ],JSON_UNESCAPED_UNICODE),
            'industryType'          => 'E_BUSINESS',
            'payType'               => 'WXPAY_SDK',
            'payAppid'              => '445454545',
            'payInfoType'           => 'payInfo' */
        ];
        return $this->execute('ordeWebCashPayQuery',$data);
    }
    
    /**
     * 收银台支付退款
     * @param array $param
     */
    public function ordeWebCashPayRefund( array $param = [] )
    {
        $data = [
            'orderId'               => '20170302000001',
            'refundAmount'          => '0.01',
            'refundOrderId'         => '20170302000001',
            'serverCallbackUrl'     => $this->config['ordeWebCashPayRefundNotifyUrl'],
        ];
        return $this->execute('ordeWebCashPayRefund',$data);
    }
    
    /**
     * 收银台支付退款查询
     * @param array $param
     */
    public function ordeWebCashPayRefundQuery( array $param = [] )
    {
        $data = [
            'refundOrderId'         => 'refundOrderId',
        ];
        return $this->execute('ordeWebCashPayRefundQuery',$data);
    }

    /**
     * 小程序支付接口
     * @param array $param
     */
    public function orderMnAppPay( array $param = [] )
    {
        $data = [
            'P1_bizType'                => 'AppPayApplet',
            'P2_orderId'                => date("YmdHis"),//订单号
            'P3_customerNumber'         => $this->config['customerNumber'],
            'P4_payType'                => 'APPLET',
            'P5_appid'                  => 'wx9dbff8f1908f55be',
            'P6_deviceInfo'             => 'WEB',
            'P7_isRaw'                  => '1',
            'P8_openid'                 => 'oLU7k5AwOwFuShUF3p26K_oTFVqw',
            'P9_orderAmount'            => '0.10',
            'P10_currency'              => 'CNY',
            'P11_appType'               => 'WXPAY',
            'P12_notifyUrl'             => $this->url['orderCallBackUrl'],
            'P13_successToUrl'          => '',
            'P14_orderIp'               => '127.0.0.1',
            'P15_goodsName'             => '在线购物',
            'P16_goodsDetail'           => '在线小程序商品',
            'P17_limitCreditPay'        => '0',
            'P18_desc'                  => '在线下单支付',
            //'subMerchantId'             => $this->config['customerNumber'],
            //'P21_goodsTag'              => '',
            //'P21_guid'                  => '',
            //'P23_marketingRule'         => '',
            /* 'P24_identity'              => json_encode([
                'number'    => '510521199009214822',
                'name'      => '小陈哥',
                'type'      => 'IDCARD'
            ],JSON_UNESCAPED_UNICODE), */
           /*  'ruleJson'                  => json_encode([
                [
                    'splitBillMerchantNo'   => 'E18xxxxxxxx',
                    'splitBillAmount'       => '0.03'
                ]
            ],JSON_UNESCAPED_UNICODE), */
            /* 'timeExpire'                => '60',
            'hbfqNum'                   => '10',
            'industryRefluxInfo'        => '10',
            'foodOrderType'             => '10',
            'storeId'                   => '10',
            'alipayStoreId'             => '10',
            'openIdType'                => '10',
            'terminalSysBindNo'         => '10',
            'sceneInfo'                 => '10' */
        ];
        return $this->execute('orderMnAppPay',$data);
    }

    /**
     * 小程序支付和收银交易订单查询接口
     * @param array $param
     */
    public function orderPayQuery( array $param = [] )
    {
        $data = [
            'P1_bizType'                => 'AppPayQuery',
            'P2_orderId'                => $param['order_sn'],//订单号
            'P3_customerNumber'         => $this->config['customerNumber'],
        ];
        return $this->execute('orderPayQuery',$data);
    }

    /**
     * 程序支付和收银交易退款接口
     * @param array $param
     */
    public function orderPayRefund( array $param = [] )
    {
        $data = [
            'P1_bizType'                => 'AppPayRefund',
            'P2_orderId'                => $param['orderId'],//订单号
            'P3_customerNumber'         => $this->config['customerNumber'],
            'P4_refundOrderId'          => $param['refundOrderId'],
            'P5_amount'                 => $param['money'],
            'P6_callbackUrl'            => $param['notifyUrl'],
        ];
        return $this->execute('orderPayRefund',$data);
    }

    /**
     * 程序支付和收银交易退款订单查询接口
     * @param array $param
     */
    public function orderPayRefundQuery( array $param = [] )
    {
        $data = [
            'P1_bizType'                => 'AppPayRefundQuery',
            'P2_refundOrderId'          => $param['refundOrderId'],//商户退款订单号,支付的订单号
            'P3_customerNumber'         => $this->config['customerNumber'],
        ];
        return $this->execute('orderPayRefundQuery',$data);
    }
    
    /**
     * 收银台主扫支付接口
     * @param array $param
     */
    public function orderCasherScanPay(array $param = [] )
    {
        $auth_code      = $param['auth_code'];
        $auth_code_prix = substr($auth_code,0,2);
        $auth_code_len  = strlen($auth_code);
        $identity=[];
        if( $auth_code_len == 18 && in_array($auth_code_prix,['13'])  ) {
            $pay_type = 'WXPAY';
            $timeExpire='60';
            $identity =[
                'number'=>$param['buyerIdcard']??'',
                'name'=>$param['buyerTruename']??'',
                'type'=>'IDCARD',
            ];
        } else if( in_array($auth_code_len,['16','17','18','19','20','21','22','23','24']) && in_array($auth_code_prix,[
            '25',
            '26',
            '27',
            '28',
            '29',
            '30',
        ])  ) {
            $pay_type = 'ALIPAY';
            $timeExpire='1m';
            $identity =[
                'name'=>$param['buyerTruename']??'',
                'cert_type'=>'IDENTITY_CARD',
                'cert_no'=>$param['buyerIdcard']??'',
                'min_age'=>1,
                'fix_buyer'=>'T',
                'need_check_info'=>'T'
            ];
        }
        
        $data = [
            'P1_bizType'                => 'AppPay',//交易类型 下单接口 
            'P2_orderId'                => $param['order_sn'],//商户系统内部订单号，要求50字符以内，同一商户号下订单号唯一
            'P3_customerNumber'         => $this->config['customerNumber'],//合利宝分配的商户号
            'P4_payType'                => 'SWIPE',//SWIPE:刷卡(被扫)SCAN:扫码(主扫)
            'P5_orderAmount'            => $param['money'],//订单金额，以元为单位，最小金额为0.01
            'P6_currency'               => 'CNY',
            'P7_authcode'               => $param['auth_code'],//授权码
            'P8_appType'                => $pay_type,//ALIPAY：支付宝WXPAY:微信UNIONPAY:银联JDPAY:京东钱包QQPAY:QQ钱包
            'P9_notifyUrl'              => $param['notifyUrl'],
            'P10_successToUrl'          => '',
            'P11_orderIp'               => $param['ip']??'127.0.0.1',
            'P12_goodsName'             => $param['goods_name'],//商品名称
            'P13_goodsDetail'           => '',
            'P14_desc'                  => '',
            'P21_identity'              => $identity,
            'timeExpire'                => $timeExpire
            
        ];
        if(!isset($param['buyerIdcard'])|| !isset($param['buyerTruename'])){
            unset($data['P21_identity']);
        }
        return $this->execute('orderCasherScanPay',$data);
    }
    
    /**
     * 支付报关接口
     * @param array $param
     */
    public function orderApplyCustom( array $param = [] )
    {
        $money = $param['money'];
//        $goodsDetailList = [
//            [
//                'goodsName'                 => '在线下单购物',
//                'goodsNum'                  => 1,
//                'goodsItemAmount'           => $money,
//                'orderAmount'               => $money,
//                'freight'                   => 0.00,
//                'goodsAmount'               => $money,
//                'tax'                       => 0.00,
//                'customsType'               => $this->config['customsType'],
//                'merchantCommerceCode'      => $param['enterpriseNum'],
//                'merchantCommerceName'      => $param['enterpriseName'],
//                'channelOrderStatus'        => 'INIT',
//                'ebusinessOrderNo'          => $param['order_sn'],
//                'notes'                     => '支付单申报'
//            ]
//        ];
        $goodsDetailList=[];
        foreach ($param['order_goods'] as $key => $value) {
            $goodsDetailList[]=[
                'goodsName'                 => $value['goodsName'],
                'goodsNum'                  => $value['goodsNum'],
                'goodsItemAmount'           => $value['goodsItemAmount'],
                'orderAmount'               => $value['orderAmount'],
                'freight'                   => $value['freight'],
                'goodsAmount'               => $value['goodsAmount'],
                'tax'                       => $value['tax'],
                'customsType'               => $this->config['customsType'],
                'merchantCommerceCode'      => $param['enterpriseNum'],
                'merchantCommerceName'      => $param['enterpriseName'],
                //'channelOrderStatus'        => 'INIT',
                'ebusinessOrderNo'          => $param['order_sn'],
                'notes'                     => '支付单申报'
            ];
        }
        $data = [
            'P1_bizType'            => 'ApplyCustomsV2',
            'P2_orderId'            => $param['order_sn'],//订单号
            'P3_customerNumber'     => $this->config['customerNumber'],
            'P4_payerName'          => $this->getOrderApplyCustom3DESData($param['buyerName']),
            'P5_idCardType'         => 'IDCARD',
            'P6_idCardNo'           => $this->getOrderApplyCustom3DESData($param['buyerIdCardNo']),
            'P7_phone'              => $this->getOrderApplyCustom3DESData($param['buyerPhone']),
            'P8_amount'             => $money,
            'P9_payDate'            => $param['payDate'],
            'P10_callbackUrl'       => $param['callbackUrl'],
            'P11_productCode'       => 'APPPAY',
            'P12_oriOrderNum'       => $param['order_sn'],
            'P13_goodsDetailList'   => json_encode($goodsDetailList,JSON_UNESCAPED_UNICODE)
        ];
        return $this->execute('orderApplyCustom',$data);
    }
    
    /**
     * 支付报关查询结果接口
     * @param array $param
     */
    public function orderQueryCustom( array $param = [] )
    {
        $data = [
            'bizType'           => 'ApplyCustomsQueryV2',
            'orderId'           => '20170302000001',
            'customerNumber'    => 'C1800000002',
        ];
        return $this->execute('orderQueryCustom',$data);
    }
    
    /**
     * FORM 表单提交
     * @param string $url
     * @param array $param
     * @return string
     */
    private function getSubmitWebForm(string $url,array $param)
    {

        $inputValue = '';
        foreach ($param as $key => $value ) {
            $inputValue .= "<input type='hidden' name='{$key}' id='{$key}' value='{$value}' />";
        }
        
        return <<<EOF
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body onload="document.getElementById('from1').submit()">
    <form method="post" id="from1" action="{$url}">
      {$inputValue}
    </form>
</body>
</html>
EOF;
    }
    
    /**
     * 生成16位SM4随机秘钥
     */
    private function generateRandomKey()
    {
        $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $len = strlen($str)-1;
        $randstr = '';
        for ($i=0;$i<16;$i++) {
            $num=mt_rand(0,$len);
            $randstr .= $str[$num];
        }
        return $randstr;
    }
    
    /**
     * 获取合利宝公钥
     * @return void
     */
    private function getHelipayPublicKey()
    {
        $path = __DIR__.'/HelipayKey/'.$this->config['helipayPublicKey'];
        $cer_public_content = str_replace(PHP_EOL,'',file_get_contents($path));
        $data=[
            'public_key'    => $cer_public_content,
        ];
        $parameter = [
            [
                'tag'       => 'HeliPay_getHelipayPublicKey',
                'url'       => $this->config['sm2GetSignGateWay'].'/Guomi/getHelipayPublicKey',
                'data'      => $data,
                'method'    => 'POST',
                'format'    => 'x-www-form-urlencoded',
                'header'    => []
            ],
        ];
        $resTask    = TaskWorker::instance()->addTask($parameter);
        $resTask    = current($resTask);
        $result=$resTask['response']['result'];
        $result_http = json_decode($result,true);
        return $result_http['data']['cerPublicKey'];
    }
    
    /**
     * 使用合利宝公钥对数据进行sm2加密
     * @param $plaintext 明文
     * @return void 密文
     */
    private function sm2DoEncrypt($plaintext)
    {
        $cerPublicKey = $this ->getHelipayPublicKey();
        $data=[
            'public_key'    => $cerPublicKey,
            'data'  => $plaintext
        ];
        $parameter = [
            [
                'tag'       => 'HeliPay_sm2DoEncrypt',
                'url'       => $this->config['sm2GetSignGateWay'].'/Guomi/sm2DoEncrypt',
                'data'      => $data,
                'method'    => 'POST',
                'format'    => 'x-www-form-urlencoded',
                'header'    => []
            ],
        ];
        $resTask    = TaskWorker::instance()->addTask($parameter);
        $resTask    = current($resTask);
        $result=$resTask['response']['result'];
        $result_http = json_decode($result,true);
        return $result_http['data']['encryptedData'];
    }
    
    /**
     * 使用商户私钥对数据进行sm2解密
     * @param $ciphertext 密文
     * @return void 明文
     */
    private function sm2DoDecrypt($ciphertext)
    {
        $privateKey = $this ->getCustomerPrivate();
        $data=[
            'private_key'   => $this->getCustomerPrivate(),
            'data'          => $ciphertext
        ];
        $parameter = [
            [
                'tag'       => 'HeliPay_sm2DoDecrypt',
                'url'       => $this->config['sm2GetSignGateWay'].'/Guomi/sm2DoSign',
                'data'      => $data,
                'method'    => 'POST',
                'format'    => 'x-www-form-urlencoded',
                'header'    => []
            ],
        ];
        $resTask    = TaskWorker::instance()->addTask($parameter);
        $resTask    = current($resTask);
        $result=$resTask['response']['result'];
        $result_http = json_decode($result,true);
        return $result_http['data']['encryptedData'];
    }
    
    /**
     * 使用商户私钥对数据进行sm2签名
     * @param $signStr 签名字符串
     * @return void 签名
     */
    private function sm2DoSign($signStr)
    {
        $data=[
            'private_key'   => $this->getCustomerPrivate(),
            'data'          => $signStr,
            'sm2userId'     => $this->config['sm2userId']
        ];
        $parameter = [
            [
                'tag'       => 'HeliPay_sm2DoSign',
                'url'       => $this->config['sm2GetSignGateWay'].'/Guomi/sm2DoSign',
                'data'      => $data,
                'method'    => 'POST',
                'format'    => 'x-www-form-urlencoded',
                'header'    => []
            ],
        ];
        $resTask    = TaskWorker::instance()->addTask($parameter);
        $resTask    = current($resTask);
        $result=$resTask['response']['result'];
        $result_http = json_decode($result,true);
        return $result_http['data']['encryptedData'];
    }
    
    /**
     * 获取商户私钥
     * @return string|void
     */
    private function getCustomerPrivate()
    {
        $customerPrivateKeyPath = __DIR__.'/HelipayKey/'.$this->config['customerPrivateKey'];
        $customerPrivateKey = file_get_contents($customerPrivateKeyPath);
        $data=[
            'private_key'           => $customerPrivateKey,
            'customerPrivatePwd'    => $this->config['customerPrivatePwd']
        ];
        $parameter = [
            [
                'tag'       => 'HeliPay_getCustomerPrivate',
                'url'       => $this->config['sm2GetSignGateWay'].'/Guomi/getCustomerPrivate',
                'data'      => $data,
                'method'    => 'POST',
                'format'    => 'x-www-form-urlencoded',
                'header'    => []
            ],
        ];
        $resTask    = TaskWorker::instance()->addTask($parameter);
        $resTask    = current($resTask);
        $result=$resTask['response']['result'];
        $result_http = json_decode($result,true);
        return $result_http['data']['privateKey'];
    }
    
    /**
     * 获取收银台接口签名
     * @param array $param
     */
    private function getOrderCashSignData( array $param)
    {
        //生成16位SM4随机秘钥
        $sm4Key         = $this->generateRandomKey();
        //加密后的SM4密钥
        $encrytionKey   = $this->sm2DoEncrypt($sm4Key);
        //使用SM4随机秘钥对data数据进行加密
        // 加密
        $encryptedData  = openssl_encrypt(json_encode($param), 'sm4-cbc', $sm4Key, OPENSSL_RAW_DATA, base64_decode($this->config['sm4Iv']));
        // Base64编码
        $data           = base64_encode($encryptedData);
        //签名
        $sign           = $this->sm2DoSign($data);
        //请求通道
        return [
            'data'              => $data,
            'customerNumber'    => $this->config['customerNumber'],
            'encryptionKey'     => $encrytionKey,
            'signType'          => 'SM3WITHSM2',
            'sign'              => $sign,
            'version'           => '1.0',
            'timestamp'         => time()
        ];
    }
    

    
    /**
     * 获取收银台主扫支付和小程序接口签名
     * 国密版本
     * @param array $param
     */
    private function getOrderPaySignData( array $param)
    {
        $signData= $this->getSignData($param);
        //生成16位SM4随机秘钥
        $sm4Key         = $this->generateRandomKey();
        //加密后的SM4密钥
        $encrytionKey   = $this->sm2DoEncrypt($sm4Key);
        $string         = "&".implode("&", $signData);
        $sign           = $this->sm2DoSign($string);
        //合力宝测试商户隐藏字段，需要特殊处理
        if( isset($this->config['customsEnv']) && $this->config['customsEnv'] == 'test' ) {
            $param['P20_subMerchantId'] = '74270285';
        }
    
        //signatureType 和  encryptionKey 不参与签名
        $param['signatureType'] = 'SM3WITHSM2';
        $param['sign'] = $sign;
        $param['encryptionKey'] = $encrytionKey;
        return $param;
    }
    
    /**
     * 获取3DES加密数据
     * @param array $param
     */
    private function encrypt3DES($data, $key)
    {
        $encryptedData = openssl_encrypt($data, 'des-ede3', $key, OPENSSL_RAW_DATA, '');
        return base64_encode($encryptedData);
    }

    /**
     * 获取报关敏感信息加密数据
     * @param array $param
     */
    private function getOrderApplyCustom3DESData($data)
    {
        return $this->encrypt3DES($data,$this->config['orderApplySensorInfoKey']);
    }
    
    /**
     * 获取进件签名数据
     * 开户
     * @param array $param
     */
    private function getMerchantSignData(string $method, array $data)
    {
        $jsonstr        = json_encode($data,JSON_UNESCAPED_UNICODE);
        $key            = $this->config['openUserDesKey'];
        $body           = $this->encrypt3DES($jsonstr, $key);
        $source         = $body."&".$this->config['customerNumber']."&".$this->config['openUserSecret'];
        $sign           = md5($source); // MD5签名
        return [
            'body'          => $body,
            'merchantNo'    => $this->config['customerNumber'],
            'sign'          => $sign,
            'interfaceName' => $method
        ];
    }
    
    /**
     * 获取支付单报关签名
     * @param array $param
     */
    private function getOrderApplyCustomSign(array $param)
    {
        $string = "&".implode("&", $param)."&{$this->config['orderApplyCustomSecret']}";
        $param['sign'] = md5($string);
        return $param;
    }
    
    /**
     * 过滤不签名参数
     * @param array $param
     * @return array
     */
    public function getSignData(array $param) {
        $signData=[];
        foreach ($param as $key => $value) {
            if(!in_array($key, $this->noSignData)){
                $signData[$key]=$value;
            }
        }
        return $signData;
    }
    
    /**
     * 发起请求
     * @param string $method
     * @param array $param
     * @return mixed
     */
    public function execute(string $method,array $param)
    {
        if( empty($this->url[$method]) ) {
            return Normal::returnCode(Normal::FAIL,"业务方法{$method}路由不存在!");
        }
        
        if( empty($this->url['helipayGateWay']) ) {
            return Normal::returnCode(Normal::FAIL,"合力宝网关helipayGateWay未配置!");
        }
        
        $router     = $this->url[$method];
        $url        = $this->url['helipayGateWay'].$router;
        $start_time = microtime(true);
        
        $_result_flag = 1;
        //web pc 收银台支付接口明细
        if( in_array($method,['ordeWebCashPay','ordeWebCashPayQuery','ordeWebCashPayRefund','ordeWebCashPayRefundQuery']) ) 
        {
            $param      = $this->getOrderCashSignData($param);
            $jsonStr    = json_encode($param,JSON_UNESCAPED_UNICODE);
            $header     = [
                'Content-Type: application/json; charset=utf-8',
                'Content-Length: ' . strlen($jsonStr)
            ];
            $res = Http::postJsonCurl($url,$param,$header);
        }
        //收银台主扫和小程序支付接口明细
        elseif( in_array($method,['orderCasherScanPay','orderMnAppPay','orderPayQuery','orderPayRefund','orderPayRefundQuery']) ) 
        {
            $param = $this->getOrderPaySignData($param);
            $parameter = [
                [
                    'tag'       => 'HeliPay_'.$method,
                    'url'       => $url,
                    'data'      => $param,
                    'method'    => 'POST',
                    'format'    => 'x-www-form-urlencoded',
                    'header'    => []
                ],
            ];
            $resTask    = TaskWorker::instance()->addTask($parameter);
            $resTask    = current($resTask);
            $res=$resTask['response']['result'];
            $_result_flag = 2;
        }
        //进件开户，注册，查询，电子合同签署结果查询
        elseif( in_array($method,[
            'sp_register','registerQuery','openProduct',
            'getProductConfig','modifyProductConfig',
            'contractQuery','userMerchantInfoQuery'
        ]) )
        {
            $param = $this->getMerchantSignData($method,$param);
            $res = Http::post($url,$param);
        }
        //进件开户，电子合同在线签署
        elseif( in_array($method,['signContract']) )
        {
            $param = $this->getMerchantSignData($method,$param);
            $form_html = $this->getSubmitWebForm($url,$param);
            exit($form_html);
        }
     
        //支付报关
        elseif( in_array($method,['orderApplyCustom','orderQueryCustom']) )
        {
            $param = $this->getOrderApplyCustomSign($param);
            //$res = Http::post($url,$param);
            $parameter = [
                [
                    'tag'       => 'HeliPay_'.$method,
                    'url'       => $url,
                    'data'      => $param,
                    'method'    => 'POST',
                    'format'    => 'x-www-form-urlencoded',
                    'header'    => []
                ],
            ];
            $resTask    = TaskWorker::instance()->addTask($parameter);
            $resTask    = current($resTask);
            $res=$resTask['response']['result'];
            $_result_flag = 3;
        }
    
        $resHttp = json_decode($res, true);
        if( $_result_flag == 2 ) {
            $errorMsg = $resHttp['rt3_retMsg']??'请求失败';
            if( isset($resHttp['rt2_retCode']) && ($resHttp['rt2_retCode'] == '0000' ||
                    $resHttp['rt2_retCode'] == '0075' ||
                    $resHttp['rt2_retCode'] == '0001' 
                    )
                ) {
                return Normal::returnCode(Normal::SUC,"处理成功",$resHttp);
            }
            return Normal::returnCode(Normal::FAIL,$errorMsg,$resHttp);
        }
        //申报接口
        if( $_result_flag == 3 ) {
            $errorMsg = $resHttp['rt3_retMsg']??'请求失败';
            if( isset($resHttp['rt2_retCode']) && $resHttp['rt2_retCode'] == '0000' ||
                    $resHttp['rt2_retCode'] == '0001') {
                return Normal::returnCode(Normal::SUC,"处理成功",$resHttp);
            }
            return Normal::returnCode(Normal::FAIL,$errorMsg,$resHttp);
        }
        
        $errorMsg = $resHttp['message']??'请求失败';
        if( isset($resHttp['code']) && $resHttp['code'] == '0000' ) {
            return Normal::returnCode(Normal::SUC,"处理成功",$resHttp);
        }
        return Normal::returnCode(Normal::FAIL,$errorMsg,$resHttp);
    }    
}
